package org.tsinghua.answer.config;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.tsinghua.answer.domain.security.MyUserDetails;
import org.tsinghua.answer.domain.security.MyUserDetailsService;
import org.tsinghua.answer.domain.user.User;
import org.tsinghua.answer.domain.user.UserType;

@Configuration
public class Config {
	
	@Autowired
	private MyUserDetailsService userDetailsService;

	
	public static class WebConfig extends WebMvcConfigurerAdapter {
		@Override
		public void addViewControllers(ViewControllerRegistry registry) {
			registry.addViewController("/error").setViewName("error");
		}
		
		@Override
		public void addResourceHandlers(ResourceHandlerRegistry registry) {
			registry.addResourceHandler("/video/**").addResourceLocations("file:/var/tsinghua/").setCachePeriod(3600);
		}
	}
	
	@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
	public static class MyWebSecurity extends WebSecurityConfigurerAdapter {
		
		private UserDetailsService userDetailsService;
		
		public MyWebSecurity(UserDetailsService userDetailsService) {
			this.userDetailsService=userDetailsService;
		}
		
		@Override
		protected void configure(HttpSecurity http) throws Exception {
			http.authorizeRequests()
			.antMatchers("/").permitAll()
			.antMatchers("/ts/profile").authenticated()
			.antMatchers("/ts/ianswer").authenticated()
			.antMatchers("/ts/**").permitAll()
			.antMatchers("/error").permitAll()
			.antMatchers("/regist").permitAll()
			.antMatchers("/look").permitAll()
			.anyRequest().authenticated()
			.and()
				.formLogin()
				.loginPage("/login")
				.failureUrl("/login?error")
				.successHandler(new MyAuthenticationSuccessHandler())
				.permitAll()
			.and().logout().permitAll()
			.and().rememberMe().alwaysRemember(true).userDetailsService(userDetailsService)
			.and().csrf().disable();
		}
	}
	
	public static class MyAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
		
		@Override
		protected void handle(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
				throws IOException, ServletException {
			MyUserDetails details = (MyUserDetails)authentication.getPrincipal();
			User user = details.getUser();
			String targetUrl;
			if(user.getType() == UserType.USER) {
				targetUrl = "/";
			} else {
				targetUrl = "/" + user.getType().toString().toLowerCase();
			}

			if (response.isCommitted()) {
				logger.debug("Response has already been committed. Unable to redirect to "
						+ targetUrl);
				return;
			}

			getRedirectStrategy().sendRedirect(request, response, targetUrl);
		}
	}
	
	
	@Bean
	public BCryptPasswordEncoder getPasswordEncoder() {
		return new BCryptPasswordEncoder();
	}
	
	@Bean
	public MyWebSecurity getWebSecurityConfiguration() {
		return new MyWebSecurity(userDetailsService);
	}
	
	@Bean
	public WebMvcConfigurerAdapter getMvcConfig() {
		return new WebConfig();
	}
}
